/**
   @file ctc_usw_learning_aging.c

   @author  Copyright (C) 2012 Centec Networks Inc.  All rights reserved.

   @date 2012-10-23

   @version v2.0

   This file define sys functions

 */

/****************************************************************************
*
* Header Files
*
****************************************************************************/
#include "ctc_const.h"
#include "ctc_error.h"
#include "ctc_learning_aging.h"
#include "ctc_interrupt.h"
#include "ctc_debug.h"
#include "sys_usw_common.h"
#include "sys_usw_chip.h"
#include "sys_usw_ftm.h"
#include "sys_usw_l2_fdb.h"
#include "sys_usw_interrupt.h"
#include "sys_usw_learning_aging.h"
#include "sys_usw_dma.h"
#include "sys_usw_register.h"

#include "drv_api.h"

/****************************************************************************
 *
 * Defines and Macros
 *
 *****************************************************************************/

#define NUM_8K                          (8 * 1024)
#define NUM_16K                         (16 * 1024)
#define NUM_32K                         (32 * 1024)
#define NUM_64K                         (64 * 1024)

#if (SDB_MEM_MODEL == SDB_MODE)
#define SYS_LEARNING_AGING_INIT_CHECK(lchip) return CTC_E_NONE
#else
#define SYS_LEARNING_AGING_INIT_CHECK(lchip)             \
    do {                                \
        LCHIP_CHECK(lchip);       \
        if (NULL == p_usw_la_master[lchip])  \
        { return CTC_E_NOT_INIT; }      \
    } while(0)
#endif

/****************************************************************************
 *
 * Global and Declaration
 *
 *****************************************************************************/
sys_learning_aging_master_t* p_usw_la_master[CTC_MAX_LOCAL_CHIP_NUM_PP] = {NULL};
/*for protect mutli-chip callback function*/
sal_mutex_t*             p_aging_cb_mutex = NULL;
sal_mutex_t*             p_learning_cb_mutex = NULL;

/****************************************************************************
 *
 * Function
 *
 *****************************************************************************/
#define ___LEARNING___


int32
sys_usw_learning_set_action(uint8 lchip, ctc_learning_action_info_t* p_learning_action)
{

    uint32                     cmd       = 0;
    uint32                     field_val = 0;

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_LEARNING_AGING_INIT_CHECK(lchip);
    CTC_PTR_VALID_CHECK(p_learning_action);

    if (p_learning_action->action != CTC_LEARNING_ACTION_MAC_TABLE_FULL)
    {
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "Set learning cache threshold: %d, action: %d\n",
                                   p_learning_action->value, p_learning_action->action);
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
		return CTC_E_NOT_SUPPORT;

    }

    cmd       = DRV_IOW(IpeLearningCtl_t, IpeLearningCtl_macTableFull_f);
    field_val = (p_learning_action->value) ? 1 : 0;
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &field_val));
    p_usw_la_master[lchip]->learning_disable = field_val;

    return CTC_E_NONE;
}

int32
sys_usw_learning_get_action(uint8 lchip, ctc_learning_action_info_t* p_learning_action)
{
    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_LEARNING_AGING_INIT_CHECK(lchip);
    CTC_PTR_VALID_CHECK(p_learning_action);
    
    if (p_usw_la_master[lchip]->learning_disable)
    {
        p_learning_action->action = CTC_LEARNING_ACTION_MAC_TABLE_FULL;
    }
    return CTC_E_NONE;
}


/**
1. tcam aging(lpm tcam, aging for host route), 1bit stands for 46bits ipv4 entry, total 8K
2. hash aging, 1bits stands for 85bits hash entry, total 196k
3. register aging, host0 cam(32)+flow hash(32)+host1_da(16)+host1_sa(16), total 96
Toal aging: 8k+196k+96
*/
#define ___AGING___

STATIC int32
_sys_usw_aging_get_aging_status_by_ptr(uint8 lchip, uint32 domain_type, uint32 aging_ptr, uint8 *status)
{
    DsAgingStatus_m ds_aging_status;
    uint32            status_tbl = 0;
    uint32            status_ptr = 0;
    uint32            aging_status = 0;
    uint32           tcam_aging_num = 0;
    uint32           cmd = 0;
    uint8            pp_base = SYS_PP_BASE(lchip);
    uint8            pp_id = 0;
    uint8            pp_en = CTC_IS_BIT_SET(domain_type, SYS_AGING_PP_EN_BIT);

    sys_usw_ftm_query_table_entry_num(lchip, DsAgingStatusTcam_t, &tcam_aging_num);
    tcam_aging_num = tcam_aging_num*32;
    CTC_BIT_UNSET(domain_type, SYS_AGING_PP_EN_BIT); 
    

    status_ptr = ((SYS_AGING_DOMAIN_TCAM == domain_type) || (SYS_AGING_DOMAIN_NAT_TCAM == domain_type)) ? aging_ptr : (aging_ptr - tcam_aging_num);
    status_tbl = ((SYS_AGING_DOMAIN_TCAM == domain_type) || (SYS_AGING_DOMAIN_NAT_TCAM == domain_type)) ? DsAgingStatusTcam_t : DsAgingStatusFib_t;

    cmd = DRV_IOR(status_tbl, DRV_ENTRY_FLAG);
    if (DRV_FROM_AT(lchip)&&(!pp_en))
    {
        /*bit31 means getting agingstatus from MacLearningCacheEntryValid*/
        /*bit30~bit29 means core_id*/
        if((aging_ptr >> 31) && SYS_AGING_DOMAIN_MAC_HASH == domain_type)
        {
            cmd = DRV_IOR(MacLearningCacheEntryValid_t, MacLearningCacheEntryValid_agingStatus_f);
            pp_id = pp_base + ((aging_ptr >> 29) & 0x3) * SYS_CORE_PP_NUM(lchip);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(pp_id, (aging_ptr & 0x1fffffff), DRV_CMD_PP_EN(cmd), &aging_status));
        }
        else
        {
            for (pp_id = 0; pp_id < SYS_PP_NUM(lchip); pp_id++)
            {
                CTC_ERROR_RETURN(DRV_IOCTL(pp_id + pp_base, status_ptr >> 5, DRV_CMD_PP_EN(cmd), &ds_aging_status));
                aging_status |= DRV_GET_FIELD_V(lchip, status_tbl, DsAgingStatus_array_0_agingStatus_f + (status_ptr & 0x1f), &ds_aging_status);
                if (aging_status)
                {
                    break;
                }
            }
        }

    }
    else
    {
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, status_ptr >> 5,
                           DRV_CMD_PP_EN(cmd), &ds_aging_status));
        aging_status = DRV_GET_FIELD_V(lchip, status_tbl, DsAgingStatus_array_0_agingStatus_f + (status_ptr & 0x1f), &ds_aging_status);
    }
    *status = (uint8)aging_status;

    return CTC_E_NONE;
}

int32
_sys_usw_aging_get_host0_aging_ptr(uint8 lchip, uint32 key_index, uint32* aging_ptr)
{
    uint32 cmd = 0;
    FibHost0HashLookupCtl_m fib_ctl;
    uint8 find_flag = 0;
    uint32 tcam_aging_num = 0;
    uint8 loop = 0;
    uint8 valid_level_num=0;
    uint32 index_base[7];
    uint32 aging_index_base[7];

    cmd = DRV_IOR(FibHost0HashLookupCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0,cmd, &fib_ctl));

    if(GetFibHost0HashLookupCtl(V, fibHost0Level0HashEn_f, &fib_ctl) && !GetFibHost0HashLookupCtl(V, fibHost0Level0MacKeyEn_f, &fib_ctl))
    {
        index_base[valid_level_num] = 0;
        aging_index_base[valid_level_num++] = 0;
    }
    if(GetFibHost0HashLookupCtl(V, fibHost0Level1HashEn_f, &fib_ctl) && !GetFibHost0HashLookupCtl(V, fibHost0Level1MacKeyEn_f, &fib_ctl))
    {
        index_base[valid_level_num] = GetFibHost0HashLookupCtl(V, fibHost0Level1IndexBase_f, &fib_ctl);
        aging_index_base[valid_level_num++] = GetFibHost0HashLookupCtl(V, fibHost0Level1AgingIndexBase_f, &fib_ctl);
    }
    if(GetFibHost0HashLookupCtl(V, fibHost0Level2HashEn_f, &fib_ctl) && !GetFibHost0HashLookupCtl(V, fibHost0Level2MacKeyEn_f, &fib_ctl))
    {
        index_base[valid_level_num] = GetFibHost0HashLookupCtl(V, fibHost0Level2IndexBase_f, &fib_ctl);
        aging_index_base[valid_level_num++] = GetFibHost0HashLookupCtl(V, fibHost0Level2AgingIndexBase_f, &fib_ctl);
    }
    if(GetFibHost0HashLookupCtl(V, fibHost0Level3HashEn_f, &fib_ctl) && !GetFibHost0HashLookupCtl(V, fibHost0Level3MacKeyEn_f, &fib_ctl))
    {
        index_base[valid_level_num] = GetFibHost0HashLookupCtl(V, fibHost0Level3IndexBase_f, &fib_ctl);
        aging_index_base[valid_level_num++] = GetFibHost0HashLookupCtl(V, fibHost0Level3AgingIndexBase_f, &fib_ctl);
    }
    if(GetFibHost0HashLookupCtl(V, fibHost0Level4HashEn_f, &fib_ctl) && !GetFibHost0HashLookupCtl(V, fibHost0Level4MacKeyEn_f, &fib_ctl))
    {
        index_base[valid_level_num] = GetFibHost0HashLookupCtl(V, fibHost0Level4IndexBase_f, &fib_ctl);
        aging_index_base[valid_level_num++] = GetFibHost0HashLookupCtl(V, fibHost0Level4AgingIndexBase_f, &fib_ctl);
    }
    if(GetFibHost0HashLookupCtl(V, fibHost0Level5HashEn_f, &fib_ctl) && !GetFibHost0HashLookupCtl(V, fibHost0Level5MacKeyEn_f, &fib_ctl))
    {
        index_base[valid_level_num] = GetFibHost0HashLookupCtl(V, fibHost0Level5IndexBase_f, &fib_ctl);
        aging_index_base[valid_level_num++] = GetFibHost0HashLookupCtl(V, fibHost0Level5AgingIndexBase_f, &fib_ctl);
    }
    /*process the last level*/
    sys_usw_ftm_query_table_entry_num(lchip, DsFibHost0Ipv4HashKey_t, &tcam_aging_num);
    index_base[valid_level_num] = tcam_aging_num;


    if (key_index < 32)
    {
        /*cam*/
        *aging_ptr = GetFibHost0HashLookupCtl(V, fibHost0IpLookupAgingIndexBase_f, &fib_ctl) + key_index;
        find_flag = 1;
    }
    else
    {
        for(loop=0; loop < valid_level_num; loop++)
        {
            if(key_index < index_base[loop+1] + 32)
            {
                *aging_ptr = key_index - index_base[loop] + aging_index_base[loop];
                find_flag = 1;
                break;
            }
        }
    }

    if (find_flag)
    {
        sys_usw_ftm_query_table_entry_num(lchip, DsAgingStatusTcam_t, &tcam_aging_num);
        tcam_aging_num = tcam_aging_num*32;
        *aging_ptr += tcam_aging_num;
    }
    else
    {
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "[Aging]The key-index is out of range! ");
        return CTC_E_HW_INVALID_INDEX;
    }

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging] index to AgingPtr:0x%x \n", *aging_ptr);
    return CTC_E_NONE;
}

int32
_sys_usw_aging_get_host1_aging_ptr(uint8 lchip, uint32 key_index, uint32* aging_ptr)
{
    uint32 cmd = 0;
    FibHost1HashLookupCtl_m fib_ctl;
    uint32 host1_aging_base = 0;
    uint32 fib_level_thres = 0;
    uint8 find_flag = 0;
    uint32 tcam_aging_num = 0;
    FibHost0HashAgingBase_m aging_base;

    cmd = DRV_IOR(FibHost1HashLookupCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0,cmd, &fib_ctl));
    cmd = DRV_IOR(FibHost0HashAgingBase_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &aging_base));

    host1_aging_base = GetFibHost1HashLookupCtl(V, fibHost1AgingIndexOffset_f, &fib_ctl);
    if (GetFibHost1HashLookupCtl(V, fibHost1Level0HashEn_f, &fib_ctl))
    {
        fib_level_thres = GetFibHost1HashLookupCtl(V, fibHost1Level1IndexBase_f, &fib_ctl);
        if (key_index < fib_level_thres+32)
        {
            if (DRV_IS_DUET2(lchip))
            {
                *aging_ptr = GetFibHost0HashAgingBase(V, fibHost1AgingOffset_f, &aging_base)+key_index;
            }
            else
            {
                *aging_ptr = host1_aging_base+key_index;
            }

            find_flag = 1;
            SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging]Host1 key index:0x%x, level:%u \n", key_index, 0);
        }
    }
    if (GetFibHost1HashLookupCtl(V, fibHost1Level1HashEn_f, &fib_ctl) && !find_flag)
    {
        if(DRV_IS_DUET2(lchip))
        {
            fib_level_thres += GetFibHost1HashLookupCtl(V, fibHost1Level2IndexBase_f, &fib_ctl);
            if (key_index < fib_level_thres+32)
            {
                *aging_ptr = GetFibHost0HashAgingBase(V, fibHost1Level1AgingBase_f, &aging_base)*1024 +
                        key_index - GetFibHost1HashLookupCtl(V, fibHost1Level1IndexBase_f, &fib_ctl);
                find_flag = 1;
                SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging]Host1 key index:0x%x, level:%u \n", key_index, 1);
            }
        }
        else
        {
            *aging_ptr = host1_aging_base+key_index-GetFibHost1HashLookupCtl(V, fibHost1Level1IndexBase_f, &fib_ctl)+GetFibHost1HashLookupCtl(V, fibHost1Level1AgingIndexBase_f, &fib_ctl);
            find_flag = 1;
        }

    }
    if (GetFibHost1HashLookupCtl(V, fibHost1Level2HashEn_f, &fib_ctl) && !find_flag)
    {
        fib_level_thres += GetFibHost1HashLookupCtl(V, fibHost1Level3IndexBase_f, &fib_ctl);
        if (key_index < fib_level_thres+32)
        {
            if (DRV_IS_DUET2(lchip))
            {
                *aging_ptr = GetFibHost0HashAgingBase(V, fibHost1Level2AgingBase_f, &aging_base)*1024 +
                        key_index - GetFibHost1HashLookupCtl(V, fibHost1Level2IndexBase_f, &fib_ctl);
            }
            else
            {
                *aging_ptr = host1_aging_base+key_index+8*1024;
            }
            find_flag = 1;
            SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging]Host1 key index:0x%x, level:%u \n", key_index, 2);
        }
    }
    if (GetFibHost1HashLookupCtl(V, fibHost1Level3HashEn_f, &fib_ctl) && !find_flag)
    {
        fib_level_thres += GetFibHost1HashLookupCtl(V, fibHost1Level4IndexBase_f, &fib_ctl);
        if (key_index < fib_level_thres+32)
        {
            if (DRV_IS_DUET2(lchip))
            {
                *aging_ptr = GetFibHost0HashAgingBase(V, fibHost1Level3AgingBase_f, &aging_base)*1024 +
                        key_index - GetFibHost1HashLookupCtl(V, fibHost1Level3IndexBase_f, &fib_ctl);
            }
            else
            {
                *aging_ptr = host1_aging_base+key_index+40*1024;
            }
            find_flag = 1;
            SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging]Host1 key index:0x%x, level:%u \n", key_index, 3);
        }
    }
    if (GetFibHost1HashLookupCtl(V, fibHost1Level4HashEn_f, &fib_ctl) && !find_flag)
    {
        if (DRV_IS_DUET2(lchip))
        {
            *aging_ptr = GetFibHost0HashAgingBase(V, fibHost1Level4AgingBase_f, &aging_base)*1024 +
                    key_index - GetFibHost1HashLookupCtl(V, fibHost1Level4IndexBase_f, &fib_ctl);
        }
        else
        {
            *aging_ptr = host1_aging_base+key_index+48*1024;
        }
        find_flag = 1;
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging]Host1 key index:0x%x, level:%u \n", key_index, 4);
    }

    if (find_flag)
    {
        sys_usw_ftm_query_table_entry_num(lchip, DsAgingStatusTcam_t, &tcam_aging_num);
        tcam_aging_num = tcam_aging_num*32;
        *aging_ptr += tcam_aging_num;
    }
    else
    {
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "[Aging]The key-index is out of range! ");
        return CTC_E_HW_INVALID_INDEX;
    }

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging] index to AgingPtr:0x%x \n", *aging_ptr);

    return CTC_E_NONE;
}

int32
_sys_usw_aging_get_tcam_aging_ptr(uint8 lchip, uint8 domain_type, uint32 key_index, uint32* aging_ptr)
{
    if (domain_type == SYS_AGING_DOMAIN_TCAM)
    {
        *aging_ptr = key_index;
    }
    else if (domain_type == SYS_AGING_DOMAIN_NAT_TCAM)
    {
        *aging_ptr = DRV_NAT_TCAM_MAP(lchip, key_index * 4) + DRV_CONST(DRV_NAT_TCAM_AGING_BASE);
    }

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging] Tcam aging_ptr:%d\n", *aging_ptr);
    return CTC_E_NONE;
}

int32
_sys_usw_aging_get_index_level(uint8 lchip, uint32 key_index, uint8* level)
{
    uint32* p_level =p_usw_la_master[lchip]->level_index;
    uint8 index=0;

    if (key_index < 32)
    {
        return CTC_E_HW_INVALID_INDEX;
    }
    for (index = 0; index < 6; index++)
    {
        if (key_index < p_level[index])
        {
            break;
        }
    }
    *level = index;

    return CTC_E_NONE;
}
STATIC int32
_sys_usw_aging_get_index_level_to_db(uint8 lchip)
{
    uint8  level_id = 0;

    uint8  step = FibAccelerationCtl_demarcationIndex1_f - FibAccelerationCtl_demarcationIndex0_f;
    uint32 cmd = 0;
    FibAccelerationCtl_m fib_ctl;
    uint32 tmp_index = 0;
    
    cmd = DRV_IOR(FibAccelerationCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_ctl));
    for (level_id = 0; level_id <((DRV_IS_TMM(lchip) || DRV_IS_TMG(lchip))?7: 6); level_id++)
    {
        DRV_IOR_FIELD(lchip, FibAccelerationCtl_t, FibAccelerationCtl_demarcationIndex0_f + step * level_id, &tmp_index, &fib_ctl);
        p_usw_la_master[lchip]->level_index[level_id]= tmp_index;
    }
    return CTC_E_NONE;
}

int32
sys_usw_aging_set_aging_interval(uint8 lchip, uint8 timer_idx, uint32 age_seconds)
{
#if (SDB_MEM_MODEL == SDB_MODE)
    return CTC_E_NONE;
#endif

    uint32 cmd             = 0;
    uint32 aging_interval  = 0;
    uint32 max_age_seconds = 0;
    uint32 min_age_seconds = 0;
    uint32 core_frequency  = 0;
    uint64 temp0 = 0;
    uint64 temp1 = 0;
    IpeAgingCtl_m aging_ctl;

    SYS_LEARNING_AGING_INIT_CHECK(lchip);
    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "[Aging] Set aging interval:aging_index: %d, age_seconds:%d\n", timer_idx, age_seconds);

 /*    core_frequency = sys_usw_get_core_freq(0) * 1000000 temp for testing;*/
    core_frequency = sys_usw_get_core_freq(lchip, 0) * 1000000 /DOWN_FRE_RATE;

    /* max intervale is 0xFFFFFFFF*/
    max_age_seconds = (0xFFFFFFFF / core_frequency) * (p_usw_la_master[lchip]->aging_max_ptr[timer_idx]-p_usw_la_master[lchip]->aging_min_ptr[timer_idx]);
    min_age_seconds = 1;/* need to be reconsidered */
    if (age_seconds < min_age_seconds || age_seconds > max_age_seconds)
    {
        return CTC_E_INVALID_PARAM;
    }

    temp0 = (uint64)age_seconds*core_frequency;
    temp1 = (p_usw_la_master[lchip]->aging_max_ptr[timer_idx]-p_usw_la_master[lchip]->aging_min_ptr[timer_idx]);

    aging_interval = temp0/temp1;

#ifdef EMULATION_ENV
    if (aging_interval < 100)
    {
        aging_interval = 100;
    }
#endif

    cmd = DRV_IOR(IpeAgingCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0,cmd, &aging_ctl));


    switch(timer_idx)
    {
        case SYS_AGING_TIMER_INDEX_MAC:
            SetIpeAgingCtl(V, gTimmer_0_agingInterval_f, &aging_ctl, aging_interval);
            break;
        case SYS_AGING_TIMER_INDEX_RSV:
            aging_interval = DRV_IS_DUET2(lchip) ? 5 : aging_interval;
            SetIpeAgingCtl(V, gTimmer_1_agingInterval_f, &aging_ctl, aging_interval);
            if (DRV_IS_AT(lchip))
            {
                cmd = DRV_IOW(PpAgingCtl_t, PpAgingCtl_gTimmer_1_agingInterval_f);
                CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0,cmd, &aging_interval));
            }
            break;
        case SYS_AGING_TIMER_INDEX_PENDING:
            SetIpeAgingCtl(V, gTimmer_2_agingInterval_f, &aging_ctl, aging_interval);
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }

    cmd = DRV_IOW(IpeAgingCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0,cmd, &aging_ctl));

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging] Set aging aging_interval: %u max_age_seconds:%u \n", aging_interval, max_age_seconds);

    return CTC_E_NONE;
}

int32
sys_usw_aging_get_aging_ptr(uint8 lchip, uint8 domain_type, uint32 key_index, uint32* aging_ptr)
{
    CTC_PTR_VALID_CHECK(aging_ptr);
    SYS_LEARNING_AGING_INIT_CHECK(lchip);
    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    if (MCHIP_LA(lchip)->get_aging_ptr)
    {
        CTC_ERROR_RETURN(MCHIP_LA(lchip)->get_aging_ptr(lchip, domain_type, key_index, aging_ptr));
    }

    return CTC_E_NONE;
}

int32
sys_usw_aging_get_key_index(uint8 lchip, uint32 aging_ptr, uint8* domain_type, uint32* key_index)
{

    CTC_PTR_VALID_CHECK(domain_type);
    CTC_PTR_VALID_CHECK(key_index);

    SYS_LEARNING_AGING_INIT_CHECK(lchip);

    if (MCHIP_LA(lchip)->get_key_index)
    {
        CTC_ERROR_RETURN(MCHIP_LA(lchip)->get_key_index(lchip, aging_ptr, domain_type, key_index));
    }

    return CTC_E_NONE;
}

int32
sys_usw_aging_set_aging_status(uint8 lchip, sys_aging_domain_type_t domain_type, uint32 key_index, uint8 timer, uint8 status)
{

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging] key_index:%d, domain_type:%d, timer:%d, status:%u\n",
                               key_index, domain_type, timer, status);
    SYS_LEARNING_AGING_INIT_CHECK(lchip);

    if (MCHIP_LA(lchip)->set_aging_status)
    {
        CTC_ERROR_RETURN(MCHIP_LA(lchip)->set_aging_status(lchip, domain_type, key_index, timer, status));
    }

    return CTC_E_NONE;
}

int32
sys_usw_aging_get_aging_status(uint8 lchip, sys_aging_domain_type_t domain_type, uint32 key_index, uint8* hit)
{
    uint32  aging_ptr  = 0;
    uint8   status = 0;
    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_LEARNING_AGING_INIT_CHECK(lchip);

    if (MCHIP_LA(lchip)->get_aging_ptr)
    {
        CTC_ERROR_RETURN(MCHIP_LA(lchip)->get_aging_ptr(lchip, domain_type, key_index, &aging_ptr));
    }
    CTC_ERROR_RETURN(_sys_usw_aging_get_aging_status_by_ptr(lchip, domain_type, aging_ptr, &status));

    if (NULL != hit)
    {
        *hit = status;
    }

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging] key_index:%d, domain_type:%d, hit:%d\n",
                               key_index, domain_type, hit ? *hit : 0);

    return CTC_E_NONE;
}

int32
sys_usw_aging_get_aging_timer(uint8 lchip, uint8 domain_type, uint32 key_index, uint8* p_timer)
{
    uint32            aging_ptr  = 0;
    DsAging_m        ds_aging;
	uint16 step =0;

	step = DsAging_array_1_agingIndex_f -DsAging_array_0_agingIndex_f;

    SYS_LEARNING_AGING_INIT_CHECK(lchip);
    if (MCHIP_LA(lchip)->get_aging_ptr)
    {
        CTC_ERROR_RETURN(MCHIP_LA(lchip)->get_aging_ptr(lchip, domain_type, key_index, &aging_ptr));
    }
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, aging_ptr >> 5,
                               DRV_IOR(DsAging_t, DRV_ENTRY_FLAG), &ds_aging));
    *p_timer = DRV_GET_FIELD_V(lchip, DsAging_t, DsAging_array_0_agingIndex_f + (aging_ptr & 0x1f) * step, &ds_aging);

    return CTC_E_NONE;
}

/**
   @brief This function is to set the aging properties
 */
int32
sys_usw_aging_set_property(uint8 lchip, ctc_aging_table_type_t tbl_type, ctc_aging_prop_t aging_prop, uint32 value)
{
    uint32 cmd         = 0;
    uint16 field       = 0;
    uint8  timer_index = 0;
    uint8 step = 0;

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "[Aging] Set aging property:tbl_type %d, aging_prop:%d, value:%d\n", tbl_type, aging_prop, value);

    SYS_LEARNING_AGING_INIT_CHECK(lchip);
    if (tbl_type == CTC_AGING_TBL_MAC)
    {
        timer_index = SYS_AGING_TIMER_INDEX_MAC;
    }
    else
    {
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
        return CTC_E_NOT_SUPPORT;
    }

    step = IpeAgingCtl_gTimmer_1_scanEn_f - IpeAgingCtl_gTimmer_0_scanEn_f;

    switch (aging_prop)
    {
    case CTC_AGING_PROP_FIFO_THRESHOLD:
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
        return CTC_E_NOT_SUPPORT;

    case CTC_AGING_PROP_INTERVAL:

        return(sys_usw_aging_set_aging_interval(lchip, timer_index, value));

    case CTC_AGING_PROP_STOP_SCAN_TIMER_EXPIRED:
        field = IpeAgingCtl_gTimmer_0_stopOnMaxPtr_f + (timer_index - 1) * step;
        value = !!value;
        break;

    case CTC_AGING_PROP_AGING_SCAN_EN:
        field = IpeAgingCtl_gTimmer_0_scanEn_f + (timer_index - 1) * step;
        value = !!value;
        break;

    default:
        return CTC_E_INVALID_PARAM;
    }

    cmd = DRV_IOW(IpeAgingCtl_t, field);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));

    if (DRV_FROM_TMM(lchip) && CTC_AGING_PROP_AGING_SCAN_EN == aging_prop)
    {
        field = IpeAgingCtl_gTimmer_0_agingEn_f + (timer_index - 1) * step;
        cmd = DRV_IOW(IpeAgingCtl_t, field);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
    }

    return CTC_E_NONE;
}

/**
   @brief This function is to get the aging properties
 */
int32
sys_usw_aging_get_property(uint8 lchip, ctc_aging_table_type_t tbl_type, ctc_aging_prop_t aging_prop, uint32* value)
{
    uint32 cmd         = 0;
    uint16 field       = 0;
    uint8  timer_index = 0;
    uint8  step = 0;
    uint32 core_frequency = 0;
    uint64 temp_val = 0;
    uint64 temp = 0;

    CTC_PTR_VALID_CHECK(value);
    SYS_LEARNING_AGING_INIT_CHECK(lchip);

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "[Aging] Get aging property:tbl_type %d, aging_prop:%d\n", tbl_type, aging_prop);

    if (tbl_type == CTC_AGING_TBL_MAC)
    {
        timer_index = SYS_AGING_TIMER_INDEX_MAC;
    }
    else
    {
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
		return CTC_E_NOT_SUPPORT;
    }

    step = IpeAgingCtl_gTimmer_1_scanEn_f - IpeAgingCtl_gTimmer_0_scanEn_f;

    switch (aging_prop)
    {
    case CTC_AGING_PROP_FIFO_THRESHOLD:
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
			return CTC_E_NOT_SUPPORT;


    case CTC_AGING_PROP_INTERVAL:

        field = IpeAgingCtl_gTimmer_0_agingInterval_f + (timer_index - 1) * step;
        break;

    case CTC_AGING_PROP_STOP_SCAN_TIMER_EXPIRED:
        field = IpeAgingCtl_gTimmer_0_stopOnMaxPtr_f + (timer_index - 1) * step;
        break;

    case CTC_AGING_PROP_AGING_SCAN_EN:
        field = IpeAgingCtl_gTimmer_0_scanEn_f + (timer_index - 1) * step;
        break;

    default:
        return CTC_E_INVALID_PARAM;
    }


    cmd       = DRV_IOR(IpeAgingCtl_t, field);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, value));

    if (aging_prop == CTC_AGING_PROP_INTERVAL)
    {
        core_frequency = sys_usw_get_core_freq(lchip, 0) * 1000000/DOWN_FRE_RATE;
        temp_val = (*value);
        temp = (temp_val+1)*(p_usw_la_master[lchip]->aging_max_ptr[timer_index]-p_usw_la_master[lchip]->aging_min_ptr[timer_index]);
        *value = (temp-1)/core_frequency;
    }
    return CTC_E_NONE;
}

#if defined(DUET2) || defined(TSINGMA)
int32
sys_duet2_aging_get_aging_ptr(uint8 lchip, uint8 domain_type, uint32 key_index, uint32* aging_ptr)
{
    FibAccelerationCtl_m fib_ctl;
    uint32 tcam_aging_num = 0;
    uint32 cmd = 0;
    uint32 temp_idx = 0;
    uint8 current_level = 0;

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    if (domain_type == SYS_AGING_DOMAIN_HOST1)
    {
        CTC_ERROR_RETURN(_sys_usw_aging_get_host1_aging_ptr(lchip, key_index, aging_ptr));
        return CTC_E_NONE;
    }
    else if (domain_type == SYS_AGING_DOMAIN_IP_HASH && DRV_IS_TSINGMA(lchip))
    {
        CTC_ERROR_RETURN(_sys_usw_aging_get_host0_aging_ptr(lchip, key_index, aging_ptr));
        return CTC_E_NONE;
    }
    else if((domain_type == SYS_AGING_DOMAIN_TCAM) || (domain_type == SYS_AGING_DOMAIN_NAT_TCAM))
    {
        CTC_ERROR_RETURN(_sys_usw_aging_get_tcam_aging_ptr(lchip, domain_type, key_index, aging_ptr));
        return CTC_E_NONE;
    }

    sys_usw_ftm_query_table_entry_num(lchip, DsAgingStatusTcam_t, &tcam_aging_num);
    tcam_aging_num = tcam_aging_num*32;

    cmd = DRV_IOR(FibAccelerationCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0,cmd, &fib_ctl));

    if(SYS_AGING_DOMAIN_MAC_HASH == domain_type || (SYS_AGING_DOMAIN_IP_HASH == domain_type && DRV_IS_DUET2(lchip)))
    {
        if (key_index < 32)
        {
            *aging_ptr = key_index;
        }
        else
        {
            uint8 size_mode = 0;
            temp_idx = key_index - 32;
            size_mode = GetFibAccelerationCtl(V, host0HashSizeMode_f, &fib_ctl);

            CTC_ERROR_RETURN(_sys_usw_aging_get_index_level(lchip, key_index, &current_level));

            switch (current_level)
            {
                case 0:
                case 1:
                case 2:
                    *aging_ptr = (size_mode? (temp_idx&0x7fff) : (temp_idx&0x3fff)) + 32 + 32*1024*current_level;
                    break;
                case 3:
                case 4:
                case 5:
                    *aging_ptr = (size_mode? (temp_idx&0x3fff) : (temp_idx&0x1fff)) + 32 + 32*1024*3 + 16*1024*(current_level - 3);
                    break;
                case 6:
                {
                    temp_idx = temp_idx -  GetFibAccelerationCtl(V, externalMacIndexBase_f, &fib_ctl);
                    if (GetFibAccelerationCtl(V, host0ExternalHashSizeMode_f, &fib_ctl))
                    {
                        *aging_ptr = temp_idx + GetFibAccelerationCtl(V, externalMacAgingIndexBase_f, &fib_ctl);  /* external, externalMacAgingIndexBase: 155776*/
                    }
                    else
                    {
                        *aging_ptr = (temp_idx >> 15)*64*1024 + (temp_idx&0x7FFF) + GetFibAccelerationCtl(V, externalMacAgingIndexBase_f, &fib_ctl);
                    }
                }
                default:
                    break;
            }
        }
    }

    if ((SYS_AGING_DOMAIN_TCAM != domain_type) && (SYS_AGING_DOMAIN_NAT_TCAM != domain_type))
    {
        *aging_ptr += tcam_aging_num;
    }

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "[Aging] index to AgingPtr:0x%x \n", *aging_ptr);

    return CTC_E_NONE;
}

int32
sys_duet2_aging_set_aging_status(uint8 lchip, uint8 domain_type, uint32 key_index, uint8 timer, uint8 status)
{
    int32 ret = CTC_E_NONE;
    drv_acc_in_t in;
    drv_acc_out_t out;
    uint32 cmd = 0;
    uint32 value = 0;
    uint32 aging_ptr = 0;
    uint32 aging_tcam_base = 0;
    drv_work_platform_type_t work_plarform;
    uint8 use_aging_ptr = 0;
    uint8 hit = 0;
    uint8 step = 0;
    uint32 hw_addr = 0;

    sal_memset(&in, 0, sizeof(drv_acc_in_t));
    sal_memset(&out, 0, sizeof(drv_acc_out_t));

    /*Ensure aging ptr is min ptr*/
    use_aging_ptr = (((domain_type == SYS_AGING_DOMAIN_IP_HASH) && DRV_IS_DUET2(lchip)) || domain_type == SYS_AGING_DOMAIN_MAC_HASH ) ? 0 : 1;
    CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, DsAgingStatusTcam_t, &aging_tcam_base));
    aging_tcam_base = aging_tcam_base * 32;
    drv_get_table_property(lchip, DRV_TABLE_PROP_HW_ADDR, IpeAgingScanRangeCtl_t, 0, &hw_addr);
    hw_addr += 8;

    if(use_aging_ptr)
    {
        if (domain_type == SYS_AGING_DOMAIN_HOST1)
        {
            _sys_usw_aging_get_host1_aging_ptr(lchip, key_index, &aging_ptr);
        }
        else if (domain_type == SYS_AGING_DOMAIN_IP_HASH)
        {
            _sys_usw_aging_get_host0_aging_ptr(lchip, key_index, &aging_ptr);
        }
        else if ((domain_type == SYS_AGING_DOMAIN_TCAM) || (domain_type == SYS_AGING_DOMAIN_NAT_TCAM))
        {
            _sys_usw_aging_get_tcam_aging_ptr(lchip, domain_type, key_index, &aging_ptr);
        }
        CTC_BIT_SET(in.flag, DRV_ACC_AGING_EN);
    }
    drv_get_platform_type(lchip, &work_plarform);
    sal_mutex_lock(p_usw_la_master[lchip]->p_aging_mutex);

    if (!status && (DRV_IS_DUET2(lchip) || (DRV_IS_TSINGMA(lchip)&&(domain_type == SYS_AGING_DOMAIN_TCAM || domain_type == SYS_AGING_DOMAIN_NAT_TCAM))) && work_plarform == HW_PLATFORM)
    {
        uint32 loop = 0;
        uint32 cmdr_scan = DRV_IOR(IpeAgingCtl_t, IpeAgingCtl_gTimmer_1_scanEn_f);
        /*tm only scan Tcam, so max agingptr is 16k; d2 max agingptr is 0x33060*/
        uint32 max_aging_ptr = DRV_IS_DUET2(lchip) ? (204*1024 + 96 - 1)<<13 : (16*1024 - 1)<<13;
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_aging_get_aging_status(lchip, domain_type, key_index, &hit), p_usw_la_master[lchip]->p_aging_mutex);
        if(hit == 0)
        {
            sal_mutex_unlock(p_usw_la_master[lchip]->p_aging_mutex);
            return CTC_E_NONE;
        }
        if (domain_type != SYS_AGING_DOMAIN_TCAM && domain_type != SYS_AGING_DOMAIN_NAT_TCAM)
        {
            in.type = DRV_ACC_TYPE_UPDATE;
            in.op_type = DRV_ACC_OP_BY_INDEX;
            in.index = use_aging_ptr?(aging_ptr-8192):key_index;
            in.timer_index = SYS_AGING_TIMER_INDEX_RSV;
            in.data = &status;
            in.tbl_id = DsAging_t;
            in.module= DRV_ACC_HASH_MODULE_AGING;
            CTC_ERROR_RETURN_WITH_UNLOCK(drv_acc_api(lchip, &in, &out), p_usw_la_master[lchip]->p_aging_mutex);
        }
        else
        {
            value = SYS_AGING_TIMER_INDEX_RSV;
            step = DsAging_array_1_agingIndex_f - DsAging_array_0_agingIndex_f;

            cmd = DRV_IOW(DsAging_t, DsAging_array_0_agingIndex_f + (aging_ptr%32)*step);
            CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, aging_ptr>>5, cmd, &value), ret, error_proc);
        }

        drv_usw_chip_write(lchip, hw_addr, max_aging_ptr);
        value = 0x64;
        CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, DRV_IOW(IpeAgingCtl_t, IpeAgingCtl_gTimmer_1_agingInterval_f), &value), ret, error_proc);
        value = 1;
        CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, DRV_IOW(IpeAgingCtl_t, IpeAgingCtl_gTimmer_1_scanEn_f), &value), ret, error_proc);

        for(loop=0; loop < 0xffffffff; loop++)
        {
            CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, cmdr_scan, &value), ret, error_proc);
            if(value == 0)
            {
                break;
            }
        }

        CTC_ERROR_GOTO(sys_usw_aging_get_aging_status(lchip, domain_type, key_index, &hit), ret, error_proc);
        if(hit == 1)
        {
            SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "[Aging] Set Aging status error, key index:0x%x, timer scan en:%d\n",key_index, value);
            ret = CTC_E_HW_FAIL;
        }

    }

error_proc:

    /*Ensure aging ptr is min ptr*/
    drv_usw_chip_write(lchip, hw_addr, p_usw_la_master[lchip]->aging_min_ptr[timer]<<13);

    /*In order to make agingptr from max to min*/
    value = 0;
    CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, DRV_IOW(IpeAgingCtl_t, IpeAgingCtl_gTimmer_1_stopOnMaxPtr_f), &value), ret, error_proc);

    value = 1;
    CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, DRV_IOW(IpeAgingCtl_t, IpeAgingCtl_gTimmer_1_scanEn_f), &value), ret, error_proc);

    value = 0;
    CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, DRV_IOW(IpeAgingCtl_t, IpeAgingCtl_gTimmer_1_scanEn_f), &value), ret, error_proc);

    value = 1;
    CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, DRV_IOW(IpeAgingCtl_t, IpeAgingCtl_gTimmer_1_stopOnMaxPtr_f), &value), ret, error_proc);

    drv_usw_chip_write(lchip, hw_addr, p_usw_la_master[lchip]->aging_max_ptr[timer]<<13);

    if (domain_type != SYS_AGING_DOMAIN_TCAM && domain_type != SYS_AGING_DOMAIN_NAT_TCAM)
    {
        in.type = DRV_ACC_TYPE_UPDATE;
        in.op_type = DRV_ACC_OP_BY_INDEX;
        in.index = use_aging_ptr? (aging_ptr - aging_tcam_base) : key_index;

        in.timer_index = timer;
        in.data = &status;
        in.tbl_id = DsAging_t;
        in.module= DRV_ACC_HASH_MODULE_AGING;
        ret = drv_acc_api(lchip, &in, &out);
    }
    else
    {
        value = 0;
        step = DsAging_array_1_agingIndex_f - DsAging_array_0_agingIndex_f;
        cmd = DRV_IOW(DsAging_t, DsAging_array_0_agingIndex_f + (aging_ptr % 32)*step);
        DRV_FIELD_IOCTL(lchip, aging_ptr >> 5, cmd, &value);

        sys_usw_aging_set_aging_interval(lchip, SYS_AGING_TIMER_INDEX_RSV, 30);
    }
    sal_mutex_unlock(p_usw_la_master[lchip]->p_aging_mutex);
    return ret;
}

int32
sys_dute2_aging_get_key_index(uint8 lchip, uint32 aging_ptr, uint8* domain_type, uint32* key_index)
{
    uint32 aging_idx = 0;
    uint8  level_id = 0;
    uint32 level_used[6] = {0};
    FibAccelerationCtl_m fib_ctl;
    uint32 cmd = 0;
    uint32 hash_en = 0;
    uint32 couple_mode = 0;
    uint32 tcam_aging_num = 0;
    uint8  step = FibAccelerationCtl_host0Level1HashEn_f - FibAccelerationCtl_host0Level0HashEn_f;

    sys_usw_ftm_query_table_entry_num(lchip, DsAgingStatusTcam_t, &tcam_aging_num);
    tcam_aging_num = tcam_aging_num*32;
    cmd = DRV_IOR(FibAccelerationCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_ctl));

    if (DRV_IS_DUET2(lchip) || DRV_IS_TSINGMA(lchip))
    {
        for (level_id = 0; level_id < 6; level_id++)
        {
            DRV_IOR_FIELD(lchip, FibAccelerationCtl_t, FibAccelerationCtl_host0Level0HashEn_f + step*level_id, &hash_en, &fib_ctl);
            DRV_IOR_FIELD(lchip, FibAccelerationCtl_t, FibAccelerationCtl_host0HashSizeMode_f + step*level_id, &couple_mode, &fib_ctl);

            if (level_id <= 3)
            {
                level_used[level_id] = hash_en? (couple_mode? 0 : NUM_16K) : NUM_32K;
            }
            else
            {
                level_used[level_id] = hash_en? (couple_mode? 0 : NUM_8K) : NUM_16K;
            }
        }

        if (aging_ptr < tcam_aging_num)
        {
            uint32 entry_num = 0;
            CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, DsLpmTcamIpv4HalfKey_t, &entry_num));
            /*Tcam or Tcam Nat aging*/
            if (aging_ptr >= entry_num)
            {
                *domain_type = SYS_AGING_DOMAIN_NAT_TCAM;
                *key_index   = (aging_ptr - entry_num) / 4;
            }
            else
            {
                *domain_type = SYS_AGING_DOMAIN_TCAM;
                *key_index   = aging_ptr;
            }
        }
        else
        {
            aging_idx = aging_ptr - tcam_aging_num;

            if (aging_idx < 32)
            {
                /*Host0 cam*/
                *domain_type = SYS_AGING_DOMAIN_MAC_HASH;
                *key_index   = aging_idx;
            }
            else
            {
                *domain_type = SYS_AGING_DOMAIN_MAC_HASH;

                aging_idx = aging_idx - 32;
                level_id = aging_idx / NUM_32K;
                if (level_id == 0)
                {
                    /*Level 0 32K */
                    *key_index   = aging_idx;
                }
                else if (level_id == 1)
                {
                    /*Level 1 32K */
                    *key_index   = aging_idx - level_used[0];
                }
                else if (level_id == 2)
                {
                    /*Level 2 32K */
                    *key_index   = aging_idx - level_used[0] - level_used[1];
                }
                else
                {
                    level_id = aging_idx / NUM_16K;
                    if (level_id == 6)
                    {
                        /*Level 3 16K*/
                        *key_index   = aging_idx - level_used[0] - level_used[1] - level_used[2];
                    }
                    else if (level_id == 7)
                    {
                        /*Level 4 16K*/
                        *key_index   = aging_idx - level_used[0] - level_used[1] - level_used[2] - level_used[3];
                    }
                    else if (level_id == 8)
                    {
                        /*level 5 16K*/
                        *key_index   = aging_idx - level_used[0] - level_used[1] - level_used[2] - level_used[3] - level_used[4];
                    }
                }
            }
        }
    }

    return CTC_E_NONE;
}

#endif

#define __LEARNING_AGING__
int32
sys_usw_learning_aging_set_hw_sync(uint8 lchip, uint8 b_sync)
{
    FibAccelerationCtl_m fib_acc_ctl;
    uint32                 cmd = 0;
    uint32 hw_learning = 0;
    uint32 dma_sync = 0;
    uint32 ignore_dma = 0;
    uint8 learn_cache_en = DRV_FROM_AT(lchip) && (drv_vchip_get_core_num(lchip) > 1) ? 1 : 0;

    SYS_LEARNING_AGING_INIT_CHECK(lchip);

    if (learn_cache_en)
    {
        MapMsgDestMap_m msg_map;
        sal_memset(&msg_map, 0, sizeof(MapMsgDestMap_m));

        cmd = DRV_IOR(MapMsgDestMap_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_DMA_REPORT_TYPE_LEARNING, cmd, &msg_map));
        if((GetMapMsgDestMap(V, ecpu0En_f, &msg_map) || GetMapMsgDestMap(V, ecpu1En_f, &msg_map)) && (0 == GetMapMsgDestMap(V, hcpuEn_f, &msg_map)))
        {
            SetMapMsgDestMap(V, hcpuEn_f, &msg_map, 1);
            cmd = DRV_IOW(MapMsgDestMap_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_DMA_REPORT_TYPE_LEARNING, cmd, &msg_map));
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_DMA_REPORT_TYPE_AGING, cmd, &msg_map));
            p_usw_la_master[lchip]->is_hw_sync = b_sync ? 1 : 0;
        }
    }
    else
    {
        cmd = DRV_IOR(IpeLearningCtl_t, IpeLearningCtl_fastLearningEn_f);
        DRV_FIELD_IOCTL(lchip, 0, cmd, &hw_learning);
        if (hw_learning)
        {
            dma_sync = b_sync;
            ignore_dma = (b_sync ? 0 : 1);
            p_usw_la_master[lchip]->is_hw_sync = b_sync ? 1 : 0;
        }
        else
        {
            dma_sync = 0;
            ignore_dma = 0;
        }

        cmd = DRV_IOR(FibAccelerationCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_acc_ctl));
        SetFibAccelerationCtl(V, dmaForFastLearning_f, &fib_acc_ctl, dma_sync);
        SetFibAccelerationCtl(V, dmaForFastAging_f, &fib_acc_ctl, dma_sync);
        SetFibAccelerationCtl(V, fastAgingIgnoreFifoFull_f, &fib_acc_ctl, ignore_dma);
        SetFibAccelerationCtl(V, fastLearningIgnoreFifoFull_f, &fib_acc_ctl, ignore_dma);
        cmd = DRV_IOW(FibAccelerationCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_acc_ctl));
    }
    return CTC_E_NONE;
}

int32
sys_usw_learning_aging_dump_db(uint8 lchip, sal_file_t dump_db_fp,ctc_global_dump_db_t* p_dump_param)
{
    int32 ret = CTC_E_NONE;

    SYS_LEARNING_AGING_INIT_CHECK(lchip);
    sal_mutex_lock(p_usw_la_master[lchip]->p_aging_mutex);

    SYS_DUMP_DB_LOG(dump_db_fp, "\n");
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "##Learing/Aging");
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "Master config:");
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "---------------------------------------------------");
    SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n", "aging_min_ptr[MAC]", p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_MAC]);
    SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n", "aging_max_ptr[MAC]", p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_MAC]);
    SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n", "aging_min_ptr[PENDING]", p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_PENDING]);
    SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n", "aging_max_ptr[PENDING]", p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_PENDING]);
    SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n", "aging_min_ptr[RSV]", p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_RSV]);
    SYS_DUMP_DB_LOG(dump_db_fp, "%-30s:%u\n", "aging_max_ptr[RSV]", p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_RSV]);
    SYS_DUMP_DB_LOG(dump_db_fp, "%s\n", "---------------------------------------------------");

    sal_mutex_unlock(p_usw_la_master[lchip]->p_aging_mutex);

    return ret;
}

int32 sys_usw_learning_aging_show_status(uint8 lchip)
{
    uint8 loop = 0;
    uint32 cmd = 0;
    uint8 step0 = 0;
    uint8 step1 = 0;
    IpeAgingCtl_m aging_ctl;
    IpeAgingScanRangeCtl_m scan_ctl;
    uint32 core_frequency = 0;
    uint64 tmp_val = 0;
    PpAgingCtl_m pp_aging_ctl;
    SYS_LEARNING_AGING_INIT_CHECK(lchip);

    cmd = DRV_IOR(IpeAgingCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &aging_ctl));
    cmd = DRV_IOR(IpeAgingScanRangeCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &scan_ctl));
    if (DRV_FROM_AT(lchip))
    {
        cmd = DRV_IOR(PpAgingCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &pp_aging_ctl));
    }
    step0 = IpeAgingCtl_gTimmer_1_agingInterval_f - IpeAgingCtl_gTimmer_0_agingInterval_f;
    step1 = IpeAgingScanRangeCtl_gTimmer_1_maxPtr_f - IpeAgingScanRangeCtl_gTimmer_0_maxPtr_f;
    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-33s\n", "-------- Aging Timer Info ------");

    /*loop == 1, indicates antflow agingScan, and Arctic antflow need PP aging Scan*/
    for(loop=0; loop < 3; loop++)
    {
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-s%2u: %-s\n", "Timer", loop,\
            ((1 == loop) && DRV_FROM_AT(lchip) ? GetPpAgingCtl(V,gTimmer_0_scanEn_f+step0*loop, &pp_aging_ctl):
            GetIpeAgingCtl(V,gTimmer_0_scanEn_f+step0*loop, &aging_ctl))?"enable":"disable");

        if((1 == loop) && DRV_FROM_AT(lchip))
        {
            if (!GetPpAgingCtl(V,gTimmer_0_scanEn_f+step0*loop, &pp_aging_ctl))
            {
                SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
                continue;
            }
        }
        else if (!GetIpeAgingCtl(V,gTimmer_0_scanEn_f+step0*loop, &aging_ctl))
        {
            SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
            continue;
        }
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-21s: 0x%08x\n", "    minimal index",\
            GetIpeAgingScanRangeCtl(V, gTimmer_0_minPtr_f+step1*loop, &scan_ctl));
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-21s: 0x%08x\n", "    maximal index",\
            GetIpeAgingScanRangeCtl(V, gTimmer_0_maxPtr_f+step1*loop, &scan_ctl));

        if ((1 == loop) && DRV_FROM_AT(lchip))
        {
            tmp_val =  GetPpAgingCtl(V,gTimmer_0_agingInterval_f+step0*loop, &pp_aging_ctl);
        }
        else
        {
            tmp_val =  GetIpeAgingCtl(V,gTimmer_0_agingInterval_f+step0*loop, &aging_ctl);
        }
        core_frequency = sys_usw_get_core_freq(lchip, 0) * 1000000/DOWN_FRE_RATE;
        tmp_val = ((tmp_val+1)*(p_usw_la_master[lchip]->aging_max_ptr[loop+1]-p_usw_la_master[lchip]->aging_min_ptr[loop+1])-1)/core_frequency;
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-21s: %-"PRIu64"s\n", "    aging interval",tmp_val);
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");

    }

    return CTC_E_NONE;
}

#define __SYNC_DMA_INFO__
STATIC int32
_sys_usw_learning_aging_decode_leaning_data(uint8 lchip, void* p_info, ctc_learning_cache_entry_t* p_entry)
{
    sys_learning_aging_decode_d2_t* p_learning = (sys_learning_aging_decode_d2_t*)p_info;
    hw_mac_addr_t             mac_sa   = { 0 };

    mac_sa[0] = ((p_learning->macsa_23_47 & 0x1FF) << 23) | p_learning->macsa_0_22;
    mac_sa[1] = (p_learning->macsa_23_47 >> 9) & 0xFFFF;
    SYS_USW_SET_USER_MAC(p_entry->mac, mac_sa);
    p_entry->fid                = (p_learning->vsi_id_7_13 << 7) | p_learning->vsi_id_0_6;

    if (!p_learning->is_global_src_port)
    {
        p_entry->logic_port = p_learning->learning_source_port;
        p_entry->is_logic_port = 1;
    }
    else
    {
        p_entry->is_logic_port = 0;
        p_entry->global_src_port = SYS_MAP_DRV_GPORT_TO_CTC_GPORT(p_learning->learning_source_port);
    }

    p_entry->cvlan_id = (p_learning->uShare_11_42 >> 13)&0xFFF;
    p_entry->svlan_id = ((p_learning->uShare_11_42 >> 25) & 0x7F) | ((p_learning->uShare_43_51 & 0x1F) << 7);

    p_entry->ether_oam_md_level = (p_learning->uShare_43_51 >> 5) & 0x7;
    p_entry->is_ether_oam       = (p_learning->uShare_43_51 >> 8) & 0x1;

    p_entry->mac_sa_0to31 = (p_entry->mac[5] | (p_entry->mac[4] << 8) |
        (p_entry->mac[3] << 16) | (p_entry->mac[2] << 24));
    p_entry->mac_sa_32to47 = (p_entry->mac[1] | (p_entry->mac[0] << 8));
    p_entry->is_hw_sync = p_usw_la_master[lchip]->is_hw_sync;

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_learning_aging_decode_aging_data(uint8 lchip, void* p_info, ctc_aging_info_entry_t* p_entry, uint8* is_ip)
{
    sys_learning_aging_decode_d2_t* p_aging = (sys_learning_aging_decode_d2_t*)p_info;
    uint8  hash_type = 0;
    uint32  dsmac_index = 0;
    DsMac_m dsmac;
    uint32 cmd = 0;

    hw_mac_addr_t             mac_sa   = { 0 };
    mac_addr_t mac_tmp;

    hash_type = (p_aging->uShare_11_42 >> 14) & 0x7;

    if (hash_type == DRV_ENUM(DRV_FIBHOST0PRIMARYHASHTYPE_MAC))
    {
        /*1.1 mac aging */
        mac_sa[0] = ((p_aging->macsa_23_47 & 0x1FF) << 23) | p_aging->macsa_0_22;
        mac_sa[1] = (p_aging->macsa_23_47 >> 9) & 0xFFFF;
        SYS_USW_SET_USER_MAC(p_entry->mac, mac_sa);
        p_entry->fid                = (p_aging->vsi_id_7_13 << 7) | p_aging->vsi_id_0_6;
        p_entry->is_hw_sync        = (p_aging->uShare_43_51 >> 8) & 0x1;
        p_entry->aging_type = CTC_AGING_TYPE_MAC;
        *is_ip = 0;

        dsmac_index   = p_aging->uShare_0_10 | ((p_aging->uShare_11_42 & 0x7F) << 11);
        cmd = DRV_IOR(DsMac_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, dsmac_index, cmd, &dsmac));

        p_entry->is_logic_port = GetDsMac(V, learnSource_f, &dsmac);
        if (p_entry->is_logic_port)
        {
            p_entry->gport = GetDsMac(V, logicSrcPort_f, &dsmac);
        }
        else
        {
            p_entry->gport = SYS_MAP_DRV_GPORT_TO_CTC_GPORT(GetDsMac(V, globalSrcPort_f, &dsmac));
        }
    }
    else
    {
        SYS_USW_SET_USER_MAC(mac_tmp, mac_sa);
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Invalid Aging hash type:%d, mac: %.4x.%.4x.%.4x, fid:%d\n", hash_type,
           mac_tmp[0], mac_tmp[2], mac_tmp[4], GetDmaFibLearnFifo(V, vsiId_f, p_aging));

        /*Not support*/
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
		return CTC_E_NOT_SUPPORT;
    }
    return CTC_E_NONE;
}

int32
sys_usw_learning_aging_sync_data(uint8 lchip, void* p_info)
{
    uint32                     index    = 0;
    uint32                     i        = 0;
    sys_dma_learning_info_t   * p_dma  = NULL;
    sys_learning_aging_decode_d2_t      * p_fifo = NULL;
    sys_learning_aging_decode_d2_t* p_next_fifo = NULL;
    hw_mac_addr_t             mac_sa   = { 0 };
    uint8   is_aging = 0;
    uint8 is_ip_aging = 0;
    sys_dma_info_t* p_dma_info = NULL;
    uint8 gchip = 0;
    uint32 ad_idx = 0;
    CTC_INTERRUPT_EVENT_FUNC cb = NULL;
    CTC_INTERRUPT_EVENT_FUNC aging_cb = NULL;

    CTC_PTR_VALID_CHECK(p_info);
    CTC_PTR_VALID_CHECK(p_usw_la_master[lchip]);
    SYS_LEARNING_AGING_INIT_CHECK(lchip);

    SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    p_usw_la_master[lchip]->ctc_learning.sync_mode = 1;
    p_usw_la_master[lchip]->ctc_aging.sync_mode = 1;

    p_dma_info = (sys_dma_info_t*)p_info;
    CTC_ERROR_RETURN(sys_usw_interrupt_get_event_cb(lchip, CTC_EVENT_L2_SW_LEARNING, &cb));
    CTC_ERROR_RETURN(sys_usw_interrupt_get_event_cb(lchip, CTC_EVENT_L2_SW_AGING, &aging_cb));
    CTC_ERROR_RETURN(sys_usw_get_gchip_id(lchip, &gchip));

    p_dma = (sys_dma_learning_info_t *) p_dma_info->p_data;

    for (i = 0; i < p_dma_info->entry_num; i++)
    {
        p_fifo   = (sys_learning_aging_decode_d2_t*)(&p_dma[i].learn_info);

        is_aging  = !(p_fifo->is_learning);

        if (!is_aging)
        {
            _sys_usw_learning_aging_decode_leaning_data(lchip, p_fifo, &(p_usw_la_master[lchip]->ctc_learning.learning_entry[index]));
            p_usw_la_master[lchip]->ctc_learning.entry_num = (++index);
        }
        else
        {
            if ((((p_fifo->uShare_11_42 >> 14) & 0x7) == DRV_ENUM(DRV_FIBHOST0PRIMARYHASHTYPE_MAC)) &&
                p_fifo->is_global_src_port)
            {
                /*for pending aging , sdk process direct , do not sync to sys*/
                p_usw_la_master[lchip]->l2_addr.fid = (p_fifo->vsi_id_7_13 << 7) | p_fifo->vsi_id_0_6;
                ad_idx = ((p_fifo->uShare_11_42 & 0x7F) << 11) | p_fifo->uShare_0_10;

                mac_sa[0] = ((p_fifo->macsa_23_47 & 0x1FF) << 23) | p_fifo->macsa_0_22;
                mac_sa[1] = (p_fifo->macsa_23_47 >> 9) & 0xFFFF;
                SYS_USW_SET_USER_MAC(p_usw_la_master[lchip]->l2_addr.mac, mac_sa);
                CTC_ERROR_RETURN(sys_usw_l2_remove_pending_fdb(lchip, &p_usw_la_master[lchip]->l2_addr, ad_idx));
            }
            else
            {
                _sys_usw_learning_aging_decode_aging_data(lchip, p_fifo, &(p_usw_la_master[lchip]->ctc_aging.aging_entry[index]), &is_ip_aging);
                p_usw_la_master[lchip]->ctc_aging.fifo_idx_num = (++index);
            }

        }

        p_next_fifo  = ((i + 1) == p_dma_info->entry_num) ? NULL : (sys_learning_aging_decode_d2_t*)(&p_dma[i + 1].learn_info);

        if(!p_next_fifo || (is_aging != !(p_next_fifo->is_learning))
            || ((aging_cb && (CTC_LEARNING_CACHE_MAX_INDEX == p_usw_la_master[lchip]->ctc_aging.fifo_idx_num)))
            || (cb && (CTC_LEARNING_CACHE_MAX_INDEX == p_usw_la_master[lchip]->ctc_learning.entry_num)))
        {
            if (p_learning_cb_mutex)
            {
                sal_mutex_lock(p_learning_cb_mutex);
            }

            if(aging_cb && p_usw_la_master[lchip]->ctc_aging.fifo_idx_num)
            {
                aging_cb(gchip, &p_usw_la_master[lchip]->ctc_aging);
                p_usw_la_master[lchip]->ctc_aging.fifo_idx_num = 0;
            }
            else if(cb && p_usw_la_master[lchip]->ctc_learning.entry_num)
            {
                cb(gchip, &p_usw_la_master[lchip]->ctc_learning);
                p_usw_la_master[lchip]->ctc_learning.entry_num = 0;
            }
            index = 0;

            if (p_learning_cb_mutex)
            {
                sal_mutex_unlock(p_learning_cb_mutex);
            }
        }
    }

    return CTC_E_NONE;
}

#define ___INIT_DEINIT___

STATIC int32
_sys_usw_aging_set_register(uint8 lchip)
{
    uint32 cmd = 0;
    FibAccelerationCtl_m fib_acc_ctl;
    /* 1. mac hash dem */
    cmd = DRV_IOR(FibAccelerationCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_acc_ctl));

    SetFibAccelerationCtl(V, levelNum0_f, &fib_acc_ctl, 0);
    SetFibAccelerationCtl(V, levelNum1_f, &fib_acc_ctl, 1);
    SetFibAccelerationCtl(V, levelNum2_f, &fib_acc_ctl, 2);
    SetFibAccelerationCtl(V, levelNum3_f, &fib_acc_ctl, 3);
    SetFibAccelerationCtl(V, levelNum4_f, &fib_acc_ctl, 4);
    SetFibAccelerationCtl(V, levelNum5_f, &fib_acc_ctl, 5);
    /* TsingMa.MX Start */
    /* new add fields for TsingMa.MX */
    SetFibAccelerationCtl(V, levelNum6_f, &fib_acc_ctl, 6);
    /* TsingMa.MX end */

    SetFibAccelerationCtl(V, macAgingTimerIndex0_f, &fib_acc_ctl, 1);   /*used for normal aging*/
    SetFibAccelerationCtl(V, macAgingTimerIndex1_f, &fib_acc_ctl, 3);   /*used for pending aging*/
    SetFibAccelerationCtl(V, macAgingTimerSelect_f, &fib_acc_ctl, 1);
    if (DRV_FROM_AT(lchip))
    {
        SetFibAccelerationCtl(V, maxLpmTcamAgingNum_f, &fib_acc_ctl, TCAM_AGING_NUM);
    }
    cmd = DRV_IOW(FibAccelerationCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_acc_ctl));

    return CTC_E_NONE;
}

/*
    Aging timer0: for normal  fdb entry aging
    Aging timer1: for ipuc entry aging
    Aging timer2: for pending fdb entry aging
*/
STATIC int32
_sys_usw_aging_init(uint8 lchip, ctc_learn_aging_global_cfg_t* cfg)
{
    IpeAgingCtl_m                ipe_aging_ctl;
    IpeAgingScanRangeCtl_m     ipe_aging_range0;
    FibEngineLookupResultCtl_m fib_ctl;
    uint32                         cmd            = 0;
    uint32 val = 0;
    FibHost0HashAgingBase_m   aging_base;
    uint32 aging_max_ptr = 0;
    uint32 aging_min_ptr = 0;
    PpAgingCtl_m pp_aging_ctl;
    PpAgingScanRangeCtl_m pp_aging_rang;

    CTC_ERROR_RETURN(_sys_usw_aging_set_register(lchip));

    if (MCHIP_LA(lchip)->set_register)
    {
        CTC_ERROR_RETURN(MCHIP_LA(lchip)->set_register(lchip));
    }

    /* Config FDB Aging Scan Ptr*/
    if (DRV_IS_DUET2(lchip))
    {
        aging_max_ptr = 8*1024 + 196*1024 + 96 - 1;  /*8k+196k+96 = 0x33060*/
        aging_min_ptr = 8*1024;

        cmd = DRV_IOR(FibHost0HashAgingBase_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &aging_base));

        /*For host1 aging base, must 1k align, because of RTL process*/
        val = 148480; /*level0 base:144*1024+64, for 1k align using 145k*/
        SetFibHost0HashAgingBase(V, fibHost1AgingOffset_f, &aging_base, val);
        val = 161;    /*level1 base:145k+16K*/
        SetFibHost0HashAgingBase(V, fibHost1Level1AgingBase_f, &aging_base, val);
        val = 177;    /*level2 base:145k+16K+16k*/
        SetFibHost0HashAgingBase(V, fibHost1Level2AgingBase_f, &aging_base, val);
        val = 185;    /*level3 base:145k+16K+16k+8k*/
        SetFibHost0HashAgingBase(V, fibHost1Level3AgingBase_f, &aging_base, val);
        val = 193;    /*level4 base:145k+16K+16k+8k+8k*/
        SetFibHost0HashAgingBase(V, fibHost1Level4AgingBase_f, &aging_base, val);
        cmd = DRV_IOW(FibHost0HashAgingBase_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &aging_base));
    }
    else if (DRV_IS_TSINGMA(lchip))
    {
        aging_max_ptr = 13572*32 - 1;  /*8k+196k+96 = 0x33060*/
        aging_min_ptr = (16*1024);
    }
    else if(DRV_IS_TMM(lchip))
    {
        FibHost0HashLookupCtl_m fib_ctl;
        aging_max_ptr = 32 + 64*1024;
        sal_memset(&fib_ctl, 0, sizeof(fib_ctl));
        cmd = DRV_IOR(FibHost0HashLookupCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_ctl));
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level6HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 1179680;    /*32 + 64*1024 + 192*1024 + 192*1024 + 192*1024 + 256*1024 + 256*1024*/
        }
        else if (GetFibHost0HashLookupCtl(V, fibHost0L2Level5HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 917536;    /*32 + 64*1024 + 192*1024 + 192*1024 + 192*1024 + 256*1024*/
        }
        else if (GetFibHost0HashLookupCtl(V, fibHost0L2Level4HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 655392;    /*32 + 64*1024 + 192*1024 + 192*1024 + 192*1024*/
        }
        else if (GetFibHost0HashLookupCtl(V, fibHost0L2Level3HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 458784;    /*32 + 64*1024 + 192*1024 + 192*1024*/
        }
        else if (GetFibHost0HashLookupCtl(V, fibHost0L2Level2HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 262176;    /*32 + 64*1024 + 192*1024*/
        }
        aging_min_ptr = (32*1024);
        aging_max_ptr = aging_min_ptr + aging_max_ptr - 1;
    }
    else if (DRV_IS_TMG(lchip))
    {
        FibHost0HashLookupCtl_m fib_ctl;
        aging_max_ptr = 32 + 128*1024;
        sal_memset(&fib_ctl, 0, sizeof(fib_ctl));
        cmd = DRV_IOR(FibHost0HashLookupCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_ctl));
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level2HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 32 + 128*1024 + 96*1024;
        }
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level3HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 32 + 128*1024 + 96*1024 + 96*1024;
        }
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level4HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 32 + 128*1024 + 96*1024 + 96*1024 + 96*1024;
        }
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level5HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 32 + 128*1024 + 96*1024 + 96*1024 + 96*1024 + 128*1024;
        }
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level6HashEn_f, &fib_ctl))
        {
            aging_max_ptr = 32 + 128*1024 + 96*1024 + 96*1024 + 96*1024 + 128*1024 + 128*1024;
        }
        aging_min_ptr = (16*1024);
        aging_max_ptr = aging_min_ptr + aging_max_ptr - 1;
    }
    else/* for Arctic */
    {
        FibHost0HashLookupCtl_m fib_ctl;
        sal_memset(&fib_ctl, 0, sizeof(fib_ctl));
        cmd = DRV_IOR(FibHost0HashLookupCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_ctl));
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level_0_hashEn_f, &fib_ctl))
        {
            aging_max_ptr = SYS_AGIDX_BASE_MEMORY_001;
        }
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level_1_hashEn_f, &fib_ctl))
        {
            aging_max_ptr = SYS_AGIDX_BASE_MEMORY_100;
        }
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level_2_hashEn_f, &fib_ctl))
        {
            aging_max_ptr = SYS_AGIDX_BASE_MEMORY_101;
        }
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level_3_hashEn_f, &fib_ctl))
        {
            aging_max_ptr = SYS_AGIDX_BASE_MEMORY_102;
        }
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level_4_hashEn_f, &fib_ctl))
        {
            aging_max_ptr = SYS_AGIDX_BASE_MEMORY_103;
        }
        if (GetFibHost0HashLookupCtl(V, fibHost0L2Level_5_hashEn_f, &fib_ctl))
        {
            aging_max_ptr = SYS_AGIDX_BASE_MEMORY_104;
        }
        /*fdb*/
        aging_min_ptr = TCAM_AGING_NUM;
        aging_max_ptr = aging_max_ptr  + TCAM_AGING_NUM - 1;

    }
    p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_MAC] = aging_min_ptr;
    p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_MAC] = aging_max_ptr;
    p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_PENDING] = aging_min_ptr;
    p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_PENDING] = aging_max_ptr;

    cmd = DRV_IOR(IpeAgingScanRangeCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ipe_aging_range0));
    SetIpeAgingScanRangeCtl(V, gTimmer_0_minPtr_f, &ipe_aging_range0, p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_MAC]);/*Timer0 For Normal FDB Aging*/
    SetIpeAgingScanRangeCtl(V, gTimmer_0_maxPtr_f, &ipe_aging_range0, p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_MAC]);/*Timer0 For Normal FDB Aging*/
    SetIpeAgingScanRangeCtl(V, gTimmer_2_minPtr_f, &ipe_aging_range0, p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_PENDING]);/*Timer2 For Pending FDB Aging*/
    SetIpeAgingScanRangeCtl(V, gTimmer_2_maxPtr_f, &ipe_aging_range0, p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_PENDING]);/*Timer2 For Pending FDB Aging*/

    /* Config Antflow Aging Scan Ptr*/
    if ((DRV_IS_TMM(lchip) || DRV_IS_TMG(lchip)))
    {
        /*aging_max_ptr = aging_max_ptr;*/ /*the same as fdb*/
        /*aging_min_ptr = aging_min_ptr;*/
    }
    else if (DRV_IS_AT(lchip))
    {
        aging_max_ptr = TCAM_AGING_NUM  + SYS_AGIDX_BASE_MEMORY_106 - 1;/*scan memory104~105*/
        aging_min_ptr = TCAM_AGING_NUM + SYS_AGIDX_BASE_MEMORY_104;
    }
    else
    {
        aging_min_ptr = p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_MAC];
        aging_max_ptr = p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_MAC];
    }
    p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_RSV] = aging_min_ptr;
    p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_RSV] = aging_max_ptr;

    /*Timer1 used to resolve CPU set aging status, minPtr must set to 0 for tcam aging*/
    if (DRV_FROM_TMM(lchip))
    {
        /* In DT2 and TM chip, Timer 1 used for tcam aging because spec do not support change tcam agingstatus by acc, TMM/AT Timer1 used for ant-flow aging */
        SetIpeAgingScanRangeCtl(V, gTimmer_1_minPtr_f, &ipe_aging_range0, p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_RSV]);
    }
    else
    {
        SetIpeAgingScanRangeCtl(V, gTimmer_1_minPtr_f, &ipe_aging_range0, 0);
    }
    SetIpeAgingScanRangeCtl(V, gTimmer_1_maxPtr_f, &ipe_aging_range0, p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_RSV]);

    cmd = DRV_IOW(IpeAgingScanRangeCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ipe_aging_range0));


    if (DRV_FROM_AT(lchip))
    {
        /*AntFlow Aging*/
        cmd = DRV_IOR(PpAgingCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &pp_aging_ctl));
        cmd = DRV_IOR(PpAgingScanRangeCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &pp_aging_rang));

        SetPpAgingCtl(V, agingIndexValid_f, &pp_aging_ctl, 1);
        SetPpAgingCtl(V, maxTcamAgingNum_f, &pp_aging_ctl, TCAM_AGING_NUM);
        SetPpAgingCtl(V, hwAgingEn_f, &pp_aging_ctl, 1);

        SetPpAgingScanRangeCtl(V, gTimmer_1_minPtr_f, &pp_aging_rang, p_usw_la_master[lchip]->aging_min_ptr[SYS_AGING_TIMER_INDEX_RSV]);
        SetPpAgingScanRangeCtl(V, gTimmer_1_maxPtr_f, &pp_aging_rang, p_usw_la_master[lchip]->aging_max_ptr[SYS_AGING_TIMER_INDEX_RSV]);
        cmd = DRV_IOW(PpAgingCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &pp_aging_ctl));
        cmd = DRV_IOW(PpAgingScanRangeCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &pp_aging_rang));
    }

    /*aging interval  */
    CTC_ERROR_RETURN(sys_usw_aging_set_aging_interval(lchip, SYS_AGING_TIMER_INDEX_MAC, 30));  /*30s*/
    CTC_ERROR_RETURN(sys_usw_aging_set_aging_interval(lchip, SYS_AGING_TIMER_INDEX_RSV, 30));  /*30s*/
    CTC_ERROR_RETURN(sys_usw_aging_set_aging_interval(lchip, SYS_AGING_TIMER_INDEX_PENDING, 5*60));  /*5*60s*/

    /* IpeAgingCtl */
    cmd = DRV_IOR(IpeAgingCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ipe_aging_ctl));

    SetIpeAgingCtl(V, gTimmer_0_agingPtr_f, &ipe_aging_ctl, 0);
    SetIpeAgingCtl(V, gTimmer_1_agingPtr_f, &ipe_aging_ctl, 0);
    SetIpeAgingCtl(V, gTimmer_2_agingPtr_f, &ipe_aging_ctl, 0);
    SetIpeAgingCtl(V, gTimmer_0_scanEn_f, &ipe_aging_ctl, 0);
    SetIpeAgingCtl(V, gTimmer_1_scanEn_f, &ipe_aging_ctl, 0);
    SetIpeAgingCtl(V, gTimmer_2_scanEn_f, &ipe_aging_ctl, 1);
    SetIpeAgingCtl(V, agingIndexValid_f, &ipe_aging_ctl, 1);
    SetIpeAgingCtl(V, gTimmer_0_stopOnMaxPtr_f, &ipe_aging_ctl, 0);
    val = DRV_FROM_TMM(lchip) ? 0 : 1;
    SetIpeAgingCtl(V, gTimmer_1_stopOnMaxPtr_f, &ipe_aging_ctl, val);
    SetIpeAgingCtl(V, gTimmer_2_stopOnMaxPtr_f, &ipe_aging_ctl, 0);
    val = DRV_FROM_TMM(lchip) ? 1 : 0;
    SetIpeAgingCtl(V, gTimmer_2_agingEn_f, &ipe_aging_ctl, val);/* TsingMa 2 new added field */
    val = DRV_FROM_AT(lchip) ? TCAM_AGING_NUM : 0;
    SetIpeAgingCtl(V, maxTcamAgingNum_f, &ipe_aging_ctl, val);

    cmd = DRV_IOW(IpeAgingCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ipe_aging_ctl));

    /* FibEngineLookupResultCtl */
    cmd = DRV_IOR(FibEngineLookupResultCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_ctl));
    SetFibEngineLookupResultCtl(V, gIpv4McastLookupResultCtl_agingEn_f ,&fib_ctl, 1);
    SetFibEngineLookupResultCtl(V, gIpv4NatSaLookupResultCtl_agingEn_f ,&fib_ctl, 1);
    SetFibEngineLookupResultCtl(V, gIpv4UcastLookupResultCtl_agingEn_f ,&fib_ctl, 1);
    SetFibEngineLookupResultCtl(V, gIpv6McastLookupResultCtl_agingEn_f ,&fib_ctl, 1);
    SetFibEngineLookupResultCtl(V, gIpv6NatSaLookupResultCtl_agingEn_f ,&fib_ctl, 1);
    SetFibEngineLookupResultCtl(V, gIpv6UcastLookupResultCtl_agingEn_f ,&fib_ctl, 1);
    SetFibEngineLookupResultCtl(V, gMacDaLookupResultCtl_agingEn_f     ,&fib_ctl, 0);
    SetFibEngineLookupResultCtl(V, gMacIpv4LookupResultCtl_agingEn_f   ,&fib_ctl, 1);
    SetFibEngineLookupResultCtl(V, gMacIpv6LookupResultCtl_agingEn_f   ,&fib_ctl, 1);
    SetFibEngineLookupResultCtl(V, gMacSaLookupResultCtl_agingEn_f     ,&fib_ctl, 0);
    cmd = DRV_IOW(FibEngineLookupResultCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &fib_ctl));

    val = 1;
    cmd = DRV_IOW(IpeLearningCtl_t, IpeLearningCtl_updateAgingEn_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &val));

    sal_mutex_create(&p_usw_la_master[lchip]->p_aging_mutex);
    if(!p_usw_la_master[lchip]->p_aging_mutex)
    {
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No resource in ASIC \n");
		return CTC_E_NO_RESOURCE;
    }

    if((NULL == p_aging_cb_mutex) && (g_lchip_num > 1))
    {
        /*for protect ctc aging cb mutex*/
        sal_mutex_create(&p_aging_cb_mutex);
        if(!p_aging_cb_mutex)
        {
            SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No resource in ASIC \n");
            sal_mutex_destroy(p_usw_la_master[lchip]->p_aging_mutex);
            return CTC_E_NO_RESOURCE;
        }
    }
    if (MCHIP_LA(lchip)->aging_init)
    {
        MCHIP_LA(lchip)->aging_init(lchip);
    }
    _sys_usw_aging_get_index_level_to_db(lchip);
    
    return CTC_E_NONE;
}

STATIC int32
_sys_usw_learning_init(uint8 lchip, ctc_learn_aging_global_cfg_t* cfg)
{
    uint32 cmd = 0;
    uint32 field_val = 0;

    CTC_ERROR_RETURN(sys_usw_dma_register_cb(lchip, SYS_DMA_CB_TYPE_LERNING, sys_usw_learning_aging_sync_data));

    field_val = 1;
    cmd = DRV_IOW(IpeFwdCtl_t, IpeFwdCtl_macLearningMode_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &field_val));

    if ((NULL == p_learning_cb_mutex) && (g_lchip_num > 1))
    {
        /*for protect ctc learning cb mutex*/
        sal_mutex_create(&p_learning_cb_mutex);
        if (!p_learning_cb_mutex)
        {
            SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No resource in ASIC \n");
            return CTC_E_NO_RESOURCE;
        }
    }

    return CTC_E_NONE;
}

int32
sys_usw_learning_aging_init(uint8 lchip, ctc_learn_aging_global_cfg_t* cfg)
{
#if (SDB_MEM_MODEL == SDB_MODE)
    return CTC_E_NONE;
#endif
    if (p_usw_la_master[lchip])
    {
        return CTC_E_NONE;
    }
    SYS_VCHIP_MASTER_INIT(lchip, p_usw_la_master, CTC_FEATURE_L2);
    MALLOC_ZERO(MEM_FDB_MODULE, p_usw_la_master[lchip], sizeof(sys_learning_aging_master_t));
    if (!p_usw_la_master[lchip])
    {
        SYS_LEARNING_AGING_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not initialized \n");
        return CTC_E_NOT_INIT;

    }
    CTC_ERROR_RETURN(_sys_usw_learning_init(lchip, cfg));
    CTC_ERROR_RETURN(_sys_usw_aging_init(lchip, cfg));

    return CTC_E_NONE;
}

int32
sys_usw_learning_aging_deinit(uint8 lchip)
{
    uint8 chip_num = 0;

    LCHIP_CHECK(lchip);
    if (NULL == p_usw_la_master[lchip])
    {
        return CTC_E_NONE;
    }
    SYS_VCHIP_MASTER_DEINIT(lchip, p_usw_la_master, CTC_FEATURE_L2);
    sal_mutex_destroy(p_usw_la_master[lchip]->p_aging_mutex);
    sys_usw_chip_get_active_num(&chip_num);
    if (p_aging_cb_mutex && (1 == chip_num))
    {
        sal_mutex_destroy(p_aging_cb_mutex);
        p_aging_cb_mutex = NULL;
    }
    if (p_learning_cb_mutex && (1 == chip_num))
    {
        sal_mutex_destroy(p_learning_cb_mutex);
        p_learning_cb_mutex = NULL;
    }
    mem_free(p_usw_la_master[lchip]);

    return CTC_E_NONE;
}
